﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using LockCrypt.Core;
using LockCrypt.DAL;
using System.IO;
using Microsoft.Win32;

namespace LockCrypt.Mobile {
    public class WinMobileConfigurationManager : ICoreConfiguration, IDalConfiguration {
        //private static Dictionary<string, string> _settings = new Dictionary<string, string>();
        private static NameValueCollection _settings = new NameValueCollection();

        #region UI Configuration
        public string LastImportPath { get; set; }
        #endregion

        #region Core configuration
        public bool FirstRun { get; set; }
        public string Language { get; set; }
        #endregion

        #region DAL configuration
        /// <summary>
        /// Gets or sets the database provider.
        /// </summary>
        /// <value>The database provider.</value>
        public IDbProvider Provider { get; set; }
        #endregion

        internal static void Configure() {
            Configure(false);
        }

        /// <summary>
        /// Configures the application.
        /// </summary>
        /// <param name="forceReinitializeProvider"><c>true</c> if the database provider should be reinitialized.</param>
        internal static void Configure(bool forceReinitializeProvider) {
            _settings = new NameValueCollection();
            WinMobileConfigurationManager config = LoadConfiguration(forceReinitializeProvider);
            CoreConfigurationManager.Configure(config);
            DalConfigurationManager.Configure(config);
        }

        /// <summary>
        /// Loads the current configuration.
        /// </summary>
        /// <param name="forceReinitializeProvider"><c>true</c> if the database provider should be reinitialized.</param>
        /// <returns>The current configuration.</returns>
        public static WinMobileConfigurationManager LoadConfiguration(bool forceReinitializeProvider) {
            _settings = new NameValueCollection();
            SerializedSettings currentConfig = LoadSettings();
            IDbProvider dbProvider = null;
            if(DalConfigurationManager.Provider.GetType() != typeof(NullDbProvider) && !forceReinitializeProvider) { // existing provider which we don't want to reinitialize
                dbProvider = DalConfigurationManager.Provider;
            } else {
                EncryptionProviders encryptionAlgorithm;
                try {
                    encryptionAlgorithm = (EncryptionProviders)Enum.Parse(typeof(EncryptionProviders), currentConfig.EncryptionType, true);
                } catch {
                    encryptionAlgorithm = EncryptionProviders.None;
                }
                dbProvider = DalConfigurationManager.GetProvider(currentConfig.DBPath, Constants.DatabaseType.XML, encryptionAlgorithm, null);
            }
            WinMobileConfigurationManager config = new WinMobileConfigurationManager() {
                Provider = dbProvider,
                FirstRun = File.Exists(dbProvider.FileName),
                Language = currentConfig.Language
            };
            return config;
        }

        /// <summary>
        /// Gets the settings XML file location in the application directory.
        /// </summary>
        /// <returns></returns>
        private static string GetSettingsFilePath() {
            string directoryName = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            string settingsFilePath = Path.Combine(directoryName, "Settings.xml");
            return settingsFilePath;
        }

        public static SerializedSettings LoadSettings() {
            string settingsFilePath = GetSettingsFilePath();
            SerializedSettings settings = new SerializedSettings();
            if(File.Exists(settingsFilePath)) {
                try {
                    XDocument doc = XDocument.Parse(settingsFilePath, LoadOptions.None);
                    XElement xRoot = doc.Element("configuration"),
                             xSettings = xRoot.Element("settings");
                    IEnumerable<XElement> settingElements = xSettings.Elements("setting");
                    foreach(XElement ele in settingElements) {
                        string val = ele.Attribute("value").Value;
                        if(val.Length > 0) {
                            _settings.Add(ele.Attribute("name").Value, val);
                        }
                    }
                    XElement xDbPath = xRoot.Element("DBLocation");
                    XElement xEncryptionType = xRoot.Element("Encryption");
                    XElement xLanguage = xRoot.Element("Language");
                    if(xDbPath != null) {
                        settings.DBPath = xDbPath.Value;
                    }
                    if(xEncryptionType != null) {
                        settings.EncryptionType = xEncryptionType.Value;
                    }
                    if(xLanguage != null) {
                        settings.Language = xLanguage.Value;
                    }
                } catch {
                }
            }
            if(string.IsNullOrEmpty(settings.DBPath)) {
                settings.DBPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "LockCrypt.lce");
            }
            if(string.IsNullOrEmpty(settings.EncryptionType)) {
                settings.EncryptionType = "Aes256";
            }
            if(string.IsNullOrEmpty(settings.Language)) {
                settings.Language = "en-GB";
            }
            return settings;
        }

        /// <summary>
        /// Saves this <see cref="Settings"/> to an XML file in the application directory.
        /// </summary>
        public static void SaveConfiguration(WinMobileConfigurationManager config) {
            XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"));
            XElement root = new XElement("configuration",
                new XElement("DBLocation", config.Provider.FileName),
                new XElement("Encryption", config.Provider.Encryption.EncryptionType),
                new XElement("Language", config.Language));
            doc.Add(root);

            XElement xSettings = new XElement("settings");
            root.Add(xSettings);
            for(int i = 0; i < _settings.Count; i++) {
                if(_settings.GetKey(i) != "Password") {
                    xSettings.Add(new XElement("setting",
                       new XAttribute("name", _settings.GetKey(i)),
                       new XAttribute("value", _settings.Get(i))));
                }
            }
            string settingsFilePath = GetSettingsFilePath();
            doc.Save(settingsFilePath);
            using(RegistryKey regKey = Registry.CurrentUser.CreateSubKey("LockCrypt")) {
                regKey.SetValue("DBLocation", DalConfigurationManager.Provider.FileName);
                string iconsPath = Path.Combine(Lime49.Utils.GetApplicationPath(), "Icons");
                regKey.SetValue("IconLocation", iconsPath); // this is solely for desktop sync
                regKey.SetValue("LCMobileVersion", Constants.GetVersion().ToString(4));
            }
        }

        public class SerializedSettings {
            public string DBPath {get;set;}
            public string EncryptionType {get;set;}
            public string Language {get;set;}
        }
    }
}
